package com.echovin.esb.gateway.parameter.impl;

import com.echovin.esb.gateway.model.TwoTuple;
import com.echovin.esb.gateway.parameter.SchemaValidator;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.SAXException;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.*;
import java.util.Iterator;

@Slf4j
public class WSDLXMLSchemaValidator implements SchemaValidator {
    private static final String WSDL = "http://192.168.200.69:8090/services/CustomerService?wsdl";
    private static final String SCHEMALANG = "http://www.w3.org/2001/XMLSchema";

    @Override
    public TwoTuple<Boolean, String> schemaValidator(String requestPath, String bodyStr) {
        Boolean result = false;
        String message = null;
        try {
            //从bodyStr中解析Source
            Source source = this.sourceFromXMLStr(bodyStr);
            //从wsdl中解析Schema
            Schema schema = this.schemaFromWSDL(WSDL);
            //验证器实施/检查此对象表示的约束集。Validator -> 根据 Schema 检查 XML 文档的处理器。
            Validator validator = schema.newValidator();
            validator.validate(source);

            result = true;
        } catch (Exception e) {
            message = e.getMessage();
            log.error("XML文件通过WSDL文件校验失败:{}", e.getMessage());
        }
        return new TwoTuple(result, message);

    }

    /**
     * 从xmlStr中解析入参用于生成Source
     *
     * @param xmlStr
     * @return
     */
    private Source sourceFromXMLStr(String xmlStr) {
        try {
            //1.创建Reader对象
            SAXReader re = new SAXReader();
            //2.加载xml
            Document document = re.read(new ByteArrayInputStream(xmlStr.getBytes("UTF-8")));
            Element rootElement = document.getRootElement();
            Iterator iterator = rootElement.elementIterator();
            while (iterator.hasNext()) {
                Element element = (Element) iterator.next();
                if ("Body".equals(element.getName())) {
                    Iterator it = element.elementIterator();
                    Element el = (Element) it.next();
                    String xmlstr = el.asXML();
                    if (log.isDebugEnabled()) {
                        log.debug(xmlstr);
                    }
                    InputStream is = new ByteArrayInputStream(xmlstr.getBytes());
                    InputStreamReader in = new InputStreamReader(is, "UTF-8");
                    Source xsdsource = new StreamSource(in);
                    return xsdsource;
                }
            }
            // 解析不了Body，把整个xmlStr生成Source
            InputStream is = new ByteArrayInputStream(xmlStr.getBytes());
            InputStreamReader in = new InputStreamReader(is, "UTF-8");
            Source xsdsource = new StreamSource(in);
            return xsdsource;

        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * 从wsdl中解析Schema，用于校验xml
     *
     * @param wsdl
     * @return
     */
    private Schema schemaFromWSDL(String wsdl) {
        try {
            //1.创建Reader对象
            SAXReader re = new SAXReader();
            //2.加载xml
            Document document = re.read(wsdl);
            Element rootElement = document.getRootElement();
            Iterator iterator = rootElement.elementIterator();
            while (iterator.hasNext()) {
                Element element = (Element) iterator.next();
                if ("types".equals(element.getName())) {
                    Iterator it = element.elementIterator();
                    Element el = (Element) it.next();
                    String xmlstr = el.asXML();
                    if (log.isDebugEnabled()) {
                        log.debug(xmlstr);
                    }
                    InputStream is = new ByteArrayInputStream(xmlstr.getBytes());
                    InputStreamReader in = new InputStreamReader(is, "UTF-8");
                    Source xsdsource = new StreamSource(in);
                    SchemaFactory factory =
                            SchemaFactory.newInstance(SCHEMALANG);
                    Schema schema = factory.newSchema(xsdsource);
                    return schema;
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * 从file中解析Schema，用于校验xml
     *
     * @param fileName
     * @return
     */
    private Schema schemaFromFile(String fileName) {
        try {
            //查找支持指定模式语言的  SchemaFactory 的实现并返回它
            SchemaFactory schemaFactory =
                    SchemaFactory.newInstance(SCHEMALANG);
            // 建立验证文档文件对象，利用此文件对象所封装的文件进行schema验证
            File schemaFile = new File(fileName);
            // 利用schema工厂，接收验证文档文件对象生成Schema对象
            Schema schema = schemaFactory.newSchema(schemaFile);
            return schema;
        } catch (SAXException e) {
            log.error(e.getMessage());
        }
        return null;
    }


}
